<?php
namespace Tbf\Bundle\DatabaseBundle;
use Doctrine\DBAL\LockMode;
use Doctrine\ORM\EntityManager;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Tbf\Bundle\TbfBundle\DependencyInjection\TbfContainerAware;
use Tbf\Component\Arrays\ArrayFunction;

/**
 * 汇总各种数据库常用方法,
 * 基于doctrine2 orm
 */
class TbfDatabase{
    /** @var ContainerInterface */
    protected $container;
    public function __construct(ContainerInterface $container){
        $this->container = $container;
    }

    /**
     * 获取某张表的数据
     * 可以使用rekey_field进行排序,默认使用id进行排序
     * @param $table_name
     * @param string $rekey_field
     * @return array map[string]map[string]string
     */
    public function getTableData($table_name,$rekey_field='id'){
        $table_name = $this->getDbalConnection()->quoteIdentifier($table_name);
        $data = $this->getDbalConnection()
            ->query('select * from ' . $table_name)
            ->fetchAll(\PDO::FETCH_ASSOC);
        if (!empty($data[0][$rekey_field])) {
            $data = ArrayFunction::rekeyById($data,$rekey_field);
        }
        return $data;
    }

    /**
     * 在orm的概念上重建某张表
     * (重新生成副表关联数据,执行回调?)
     * 使用事务
     * @param $entity_name
     */
    public function ormRebuildTable($entity_name){
        $this->beginTransaction();
        //锁定表
        $data = $this->getDM()->createQueryBuilder()
            ->select('e')
            ->from($entity_name,'e')
            ->getQuery()->setLockMode(LockMode::PESSIMISTIC_WRITE)
            ->getResult();
        //1.删除所有数据
        foreach($data as $e1){
            $this->getDM()->remove($e1);
        }
        $this->getDM()->flush();

        //2.重建
        foreach($data as $e1){
            $this->getDM()->persist($e1);
        }
        $this->getDM()->flush();
        $this->commit();
    }

    /**
     * 某个数据库上的所有表名
     * @param string $database_name
     * @return array []string
     */
    public function getAllTableNameInDatabase($database_name=null){
        if ($database_name===null){
            $sql = 'show tables';
        }else{
            $sql = 'show tables from '.$this->getDbalConnection()->quoteIdentifier($database_name);
        }
        $ret = $this->getDbalConnection()->query($sql)->fetchAll();
        $output = array();
        foreach ($ret as $v1) {
            $table_name = ArrayFunction::firstValue($v1);
            $output[] = $table_name;
        }

        return $output;
    }

    /**
     * 在一张表上替换字符串
     * 使用事务
     */
    public function replaceStringOneTable($table_name,$from,$to){
        $this->beginTransaction();
        $sql = 'select * from '.$this->getDbalConnection()->quoteIdentifier($table_name).' for update';
        //锁定表
        $data = $this->getDbalConnection()
            ->fetchAll($sql);
        foreach($data as $k1=>$v1){
            foreach($v1 as $k2=>$v2){
                if (!is_string($v2)){
                    continue;
                }
                $data[$k1][$k2] = str_replace($from,$to,$v2);
            }
        }
        $this->setTableData(array($table_name=>$data));
        $this->commit();
    }
    /**
     * 设置数据库多张表上的数据
     * @param $data
     */
    public function setTableData($data){
        $this->container->get('tbf_database.set_table_data')->setTableData($data);
    }
    public function beginTransaction(){
        $this->getDbalConnection()->beginTransaction();
    }
    public function commit(){
        $this->getDbalConnection()->commit();
    }
    public function rollback(){
        $this->getDbalConnection()->rollback();
    }
    /**
     * @return \Doctrine\ORM\EntityManager
     */
    public function getDM(){
        return $this->container->get('doctrine')->getManager();
    }

    /**
     * @return \Doctrine\Dbal\Connection
     */
    public function getDbalConnection(){
        return $this->container->get('database_connection');
    }


}